/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.
 * Description: hdc core common interface.
 * Author: huawei
 * Create: 2020/5/18
 *
 * This program is free software; you can redistribute it and /or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version
 */

#ifndef _HDCDRV_CORE_COM_H_
#define _HDCDRV_CORE_COM_H_

#include "hdcdrv_cmd.h"
#include "drv_log.h"
#include "hdcdrv_mem_com.h"

#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/fs.h>

#ifdef HDC_ENV_DEVICE
#include <linux/securec.h>
#else
#include "securec.h"
#endif


#ifndef __GFP_ACCOUNT

#ifdef __GFP_KMEMCG
#define __GFP_ACCOUNT __GFP_KMEMCG /* for linux version 3.10 */
#endif

#ifdef __GFP_NOACCOUNT
#define __GFP_ACCOUNT 0 /* for linux version 4.1 */
#endif

#endif

#define module_hdcdrv "hdcdrv"

#define hdcdrv_err_limit(fmt, ...) do { \
    if (printk_ratelimit()) \
        drv_err(module_hdcdrv, "<%s:%d> " fmt, current->comm, current->tgid, ##__VA_ARGS__); \
} while (0);
#define hdcdrv_warn_limit(fmt, ...) do { \
    if (printk_ratelimit()) \
        drv_warn(module_hdcdrv, "<%s:%d> " fmt, current->comm, current->tgid, ##__VA_ARGS__); \
} while (0);
#define hdcdrv_info_limit(fmt, ...) do { \
    if (printk_ratelimit()) \
        drv_info(module_hdcdrv, "<%s:%d> " fmt, current->comm, current->tgid, ##__VA_ARGS__); \
} while (0);
#define hdcdrv_err(fmt, ...) do { \
    drv_err(module_hdcdrv, "<%s:%d> " fmt, current->comm, current->tgid, ##__VA_ARGS__); \
} while (0);
#define hdcdrv_warn(fmt, ...) do { \
    drv_warn(module_hdcdrv, "<%s:%d> " fmt, current->comm, current->tgid, ##__VA_ARGS__); \
} while (0);
#define hdcdrv_info(fmt, ...) do { \
    drv_info(module_hdcdrv, "<%s:%d> " fmt, current->comm, current->tgid, ##__VA_ARGS__); \
} while (0);
#define hdcdrv_critical_info(fmt, ...) do { \
    drv_err(module_hdcdrv, "<%s:%d> " fmt, current->comm, current->tgid, ##__VA_ARGS__); \
} while (0);

#define hdcdrv_dbg(fmt, ...) do { \
    drv_debug(module_hdcdrv, "[DEBUG]<%s:%d> " fmt, current->comm, current->tgid, ##__VA_ARGS__); \
} while (0);

#ifdef HDC_ENV_DEVICE
#define HDCDRV_DEV_MODE 0600
#else
#define HDCDRV_DEV_MODE 0640
#endif

#define HDCDRV_VALID 1
#define HDCDRV_INVALID 0

#define HDCDRV_CDEV_COUNT   1

#define HDCDRV_MEM_POOL_TYPE_TX 0
#define HDCDRV_MEM_POOL_TYPE_RX 1
#define HDCDRV_MEM_POOL_TYPE_NUM 2

#define HDCDRV_PACKET_SEGMENT (32 * 1024)
#define HDCDRV_INVALID_PACKET_SEGMENT (-1)

#define HDCDRV_RBTREE_PID 16
#define HDCDRV_RBTREE_CNT_BIT 24
#define HDCDRV_RBTREE_PID_MASK 0x000000000000FFFFull
#define HDCDRV_RBTREE_ADDR_MASK_H 0x0000FFFFFFFFFFFFull
#define HDCDRV_RBTREE_ADDR_MASK_L 0xFFFFFFFFFFFF0000ull

#define HDCDRV_SMALL_PACKET_SEGMENT (4 * 1024)
#define HDCDRV_HUGE_PACKET_SEGMENT (512 * 1024)
#define HDCDRV_SMALL_PACKET_NUMDEP_MIN          (8)     /* power of 2 */
#define HDCDRV_SMALL_PACKET_NUMDEP_MAX          (10)    /* power of 2 */
#define HDCDRV_HUGE_PACKET_NUMDEP_MIN           (4)     /* power of 2 */
#define HDCDRV_HUGE_PACKET_NUMDEP_MAX           (6)     /* power of 2 */

#define HDCDRV_USLEEP_RANGE_2000 2000
#define HDCDRV_USLEEP_RANGE_3000 3000

struct hdcdrv_cdev {
    struct cdev cdev;
    dev_t dev_no;
    struct class *cdev_class;
    struct device *dev;
};

enum VHDC_CTRL_MSG_TYPE {
    VHDC_CTRL_MSG_TYPE_SEGMENT = 1,
    VHDC_CTRL_MSG_TYPE_OPEN,
    VHDC_CTRL_MSG_TYPE_RELEASE,
    VHDC_CTRL_MSG_TYPE_ALLOC_MEM,
    VHDC_CTRL_MSG_TYPE_FREE_MEM,
    VHDC_CTRL_MSG_TYPE_ALLOC_HUGE,
    VHDC_CTRL_MSG_TYPE_FREE_HUGE,
    VHDC_CTRL_MSG_TYPE_MEMCOPY,
    VHDC_CTRL_MSG_TYPE_POOL_CHECK,
    VHDC_CTRL_MSG_TYPE_MAX,
};

struct vhdc_ctrl_msg_get_segment {
    int segment;
};

struct vhdc_ctrl_msg_open {
};

struct vhdc_ctrl_msg_release {
    unsigned long long hash;
};

struct vhdca_alloc_mem_para {
    int pool_type;
    int dev_id;
    int len;
    u32 fid;
};

struct vhdc_ctrl_msg_alloc_mempool {
    struct vhdca_alloc_mem_para mem_para;
    void *buf;
    u64 addr;
};

struct vhdc_ctrl_msg_free_mempool {
    void *buf;
};

struct vhdc_ctrl_msg_alloc_huge {
};
struct vhdc_ctrl_msg_free_huge {
};

struct vhdc_ctrl_msg_memcopy {
    void *dest;
    unsigned long destMax;
    const void *src;
    unsigned long count;
    int mode;
};

struct vhdc_ctrl_msg_pool_check {
    u32 size;
    u32 segment;
    u32 sg_cnt;
    dma_addr_t addr[HDCDRV_HUGE_PACKET_NUMDEP_MAX];
    unsigned char map[HDCDRV_HUGE_PACKET_NUMDEP_MAX];
};

struct vhdc_ctrl_msg {
    enum VHDC_CTRL_MSG_TYPE type;
    int error_code;
    union {
        struct vhdc_ctrl_msg_get_segment vhdc_segment;
        struct vhdc_ctrl_msg_open vhdc_open;
        struct vhdc_ctrl_msg_release vhdc_release;
        struct vhdc_ctrl_msg_alloc_mempool alloc_mempool;
        struct vhdc_ctrl_msg_free_mempool free_mempool;
        struct vhdc_ctrl_msg_alloc_huge alloc_huge;
        struct vhdc_ctrl_msg_free_huge free_huge;
        struct vhdc_ctrl_msg_memcopy mem_copy;
        struct vhdc_ctrl_msg_pool_check pool_check;
    };
};

struct vhdc_ioctl_msg {
    unsigned int cmd;
    unsigned long long hash;
    int copy_flag;
    int error_code;
    union hdcdrv_cmd cmd_data;
};


static inline u32 hdccom_get_fid_owner(u32 fid)
{
    return (fid > HDCDRV_DEFAULT_PM_FID) ? HDCDRV_SESSION_OWNER_VM : HDCDRV_SESSION_OWNER_PM;
}
struct hdcdrv_dma_mem {
    u64 addr;
    u32 len;
    u32 resv;
};

struct hdcdrv_ctrl_msg_sync_mem_info {
    int type;
    int error_code;
    int flag;
    int phy_addr_num;
    int mem_type;
    u32 alloc_len;
    u64 hash_va;
    long long pid;
    struct hdcdrv_dma_mem mem[0];
};

/* ctrl msy type */
#define HDCDRV_CTRL_MSG_TYPE_CONNECT 1
#define HDCDRV_CTRL_MSG_TYPE_CONNECT_REPLY 2
#define HDCDRV_CTRL_MSG_TYPE_CLOSE 3
#define HDCDRV_CTRL_MSG_TYPE_SYNC 4
#define HDCDRV_CTRL_MSG_TYPE_RESET 5
#define HDCDRV_CTRL_MSG_TYPE_CHAN_SET 6
#define HDCDRV_CTRL_MSG_TYPE_SYNC_MEM_INFO 7
#define HDCDRV_CTRL_MSG_TYPE_GET_DEV_SESSION_STAT 8
#define HDCDRV_CTRL_MSG_TYPE_GET_DEV_CHAN_STAT 9

#ifdef CFG_SOC_PLATFORM_MINIV1
#define HDCDRV_NON_TRANS_MSG_S_DESC_SIZE 0x10000 /* 64k, pcie support */
#define HDCDRV_NON_TRANS_MSG_C_DESC_SIZE 0x10000 /* 64k, pcie support */
#else
#define HDCDRV_NON_TRANS_MSG_S_DESC_SIZE 0x200000 /* 2M */
#define HDCDRV_NON_TRANS_MSG_C_DESC_SIZE 0x200000 /* 2M */
#endif

/* reserved 1k mem for non trans msg head and hdc ctrl msg head */
#define HDCDRV_MEM_MAX_PHY_NUM ((int)((HDCDRV_NON_TRANS_MSG_S_DESC_SIZE - 0x400) / sizeof(struct hdcdrv_dma_mem)))
#define HDCDRV_MAX_DMA_NODE HDCDRV_MEM_MAX_PHY_NUM

#define HDCDRV_NODE_IDLE 0
#define HDCDRV_NODE_BUSY 1
#define HDCDRV_ADD_FLAG 0
#define HDCDRV_DEL_FLAG 1
#define HDCDRV_FALSE_FLAG 0
#define HDCDRV_TRUE_FLAG 1

#define HDCDRV_RBTREE_SIDE_LOCAL 0
#define HDCDRV_RBTREE_SIDE_REMOTE 1

#define HDCDRV_RUNNING_ENV_ARM_3559 0
#define HDCDRV_RUNNING_ENV_X86_NORMAL 1
#define HDCDRV_RUNNING_ENV_DAVICI 2

#define HDCDRV_KERNEL_DEFAULT_PID (-2)

#ifdef CFG_SOC_PLATFORM_ESL_FPGA
#define HDCDRV_NODE_BUSY_WARING     2000 /* 2s for fpga */
#define HDCDRV_NODE_BUSY_TIMEOUT    50000 /* 50s for fpga */

#define HDCDRV_NODE_WAIT_TIME_MIN   0
#define HDCDRV_NODE_WAIT_TIME_MAX   30000 /* 30s for fpga */

#define HDCDRV_SESSION_DEFAULT_TIMEOUT 120000 /* 120s for fpga */
#define HDCDRV_SESSION_REMOTE_CLOSED_TIMEOUT (10 * HZ) /* 10s for fpga */
#define HDCDRV_CONN_TIMEOUT (100 * HZ) /* 100s for fpga */
#define HDCDRV_SESSION_RECLAIM_TIMEOUT (150 * HZ) /* 150s for fpga */

#define HDCDRV_TASKLET_STATUS_CHECK_TIME 10 /* 10s for fpga */
#else
#define HDCDRV_NODE_BUSY_WARING     100 /* ms */
#define HDCDRV_NODE_BUSY_TIMEOUT    5000 /* ms */

#define HDCDRV_NODE_WAIT_TIME_MIN   0
#define HDCDRV_NODE_WAIT_TIME_MAX   3000 /* ms */

#define HDCDRV_SESSION_DEFAULT_TIMEOUT 3000 /* ms */
#define HDCDRV_SESSION_REMOTE_CLOSED_TIMEOUT (3 * HZ) /* 3s */
#define HDCDRV_CONN_TIMEOUT (30 * HZ) /* 30s */
#define HDCDRV_SESSION_RECLAIM_TIMEOUT (60 * HZ) /* 60s */

#define HDCDRV_TASKLET_STATUS_CHECK_TIME 3
#endif


extern u64 hdcdrv_get_hash(u64 user_va, int pid, u32 fid);
extern u32 hdcdrv_get_mem_list_len(void);
extern bool hdcdrv_sid_check(char *dst_session_id, int dst_len, char *src_session_id, int src_len);
extern void hdcdrv_sid_gen(char *session_id, int len);
extern void hdcdrv_sid_copy(char *dst_session_id, int dst_len, char *src_session_id, int src_len);
extern void hdcdrv_node_status_busy(struct hdcdrv_fast_node *node);
extern void hdcdrv_node_status_idle(struct hdcdrv_fast_node *node);
extern void hdcdrv_node_status_idle_by_mem(struct hdcdrv_fast_mem *f_mem);
extern bool hdcdrv_node_is_timeout(int node_stamp);
extern bool hdcdrv_node_is_busy(struct hdcdrv_fast_node *node);
extern int hdcdrv_send_mem_info(struct hdcdrv_fast_mem *mem, int devid, int flag);
extern int hdcdrv_get_running_env(void);
extern void hdcdrv_unbind_mem_ctx(struct hdcdrv_fast_node *f_node);

extern long hdcdrv_non_trans_ctrl_msg_send(u32 devid, void *data, u32 in_data_len, u32 out_data_len, u32 *real_out_len);

int hdccom_register_cdev(struct hdcdrv_cdev *hcdev, const struct file_operations *fops);
void hdccom_free_cdev(struct hdcdrv_cdev *hcdev);
int hdcdrv_get_pid(void);
int hdcdrv_get_ppid(void);
struct mutex *hdcdrv_get_sync_mem_lock(int dev_id);
extern bool hdcdrv_mem_is_notify(struct hdcdrv_fast_mem *f_mem);
void* hdcdrv_get_sync_mem_buf(int dev_id);
void hdcdrv_release_free_mem(struct hdcdrv_ctx_fmem *ctx_fmem);
extern void hdcdrv_fast_mem_free_abnormal(struct hdcdrv_fast_node *f_node);
long hdcdrv_bind_mem_ctx(struct hdcdrv_ctx_fmem *ctx_fmem, struct hdcdrv_fast_node *f_node);

#endif /* _HDCDRV_CORE_COM_H_ */
